
#include "Debug.h"
#include "Log.h"
#include "simple_protocol.h"
#include "utility.h"
#include <Reader/Reader.h>

phStatus_t ultralight_read(uint8_t page, uint8_t *data){
	void* palMful = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	return phalMful_Read(palMful, page, data);
}

phStatus_t ultralight_fast_read(uint8_t pageStart, uint8_t num, uint8_t *data){
	if(num == 0){
		LOG_W("num == 0!");
		return 0;
	}
	void* palMful = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	uint8_t* buf;
	uint16_t nBytes = 0;
	uint8_t pageEnd = pageStart + num - 1;
	phStatus_t status = phalMful_FastRead(palMful, pageStart, pageEnd, &buf, &nBytes);
	if(status){
		return status;
	}
	memcpy(data, buf, nBytes);
	return status;
}

phStatus_t ultralight_write(uint8_t page, uint8_t *data){
	void* palMful = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	return phalMful_Write(palMful, page, data);
}

phStatus_t ultralight_authenticate_ulc(uint8_t *key){
	void *psKeyStore = phNfcLib_GetDataParams(PH_COMP_KEYSTORE);
	void* palMful = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	phStatus_t status;
	uint8_t ver = 0;
	uint8_t keyNo = 1;
	PH_CHECK_SUCCESS_FCT(status, phKeyStore_FormatKeyEntry(psKeyStore, keyNo, PH_KEYSTORE_KEY_TYPE_2K3DES));
	PH_CHECK_SUCCESS_FCT(status, phKeyStore_SetKeyAtPos(psKeyStore, keyNo, 0,
						 PH_KEYSTORE_KEY_TYPE_2K3DES, (uint8_t *)key, ver));
	// return phalMful_Sw_UlcAuthenticate(palMful, keyNo, ver);
	return phalMful_UlcAuthenticate(palMful, 0, keyNo, ver, 0, 0);
}

phStatus_t ultralight_authenticate_aes(uint8_t keyId, uint8_t *key){
	void *psKeyStore = phNfcLib_GetDataParams(PH_COMP_KEYSTORE);
	void* palMful = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	phStatus_t status;
	uint8_t ver = 0;
	uint8_t keyNo = 1;
	
	PH_CHECK_SUCCESS_FCT(status, phKeyStore_FormatKeyEntry(psKeyStore, keyNo, PH_KEYSTORE_KEY_TYPE_AES128));
	PH_CHECK_SUCCESS_FCT(status, phKeyStore_SetKeyAtPos(psKeyStore, keyNo, 0,
						 PH_KEYSTORE_KEY_TYPE_AES128, (uint8_t *)key, ver));
	return phalMful_AuthenticateAES(palMful, 0, keyNo, ver, 0, 0, keyId, NULL, 0);
	// return phalMful_Sw_AuthenticateAES(palMful, keyNo, ver, keyId);
}

phStatus_t ultralight_authenticate_pwd(uint8_t *pwd, uint8_t* pack){
	void* palMful = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	
	return phalMful_PwdAuth(palMful, pwd, pack);
}

phStatus_t ultralight_inc_counter(uint8_t counterAddr, uint32_t incrValue){
	void* palMful = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	return phalMful_IncrCnt(palMful, counterAddr, (uint8_t*)&incrValue);
}

phStatus_t ultralight_read_counter(uint8_t counterAddr, uint8_t* incrValue){
	void* palMful = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	return phalMful_ReadCnt(palMful, counterAddr, incrValue);
}

phStatus_t ultralight_read_sig(uint8_t* sig, uint16_t *sigLen){
	void* palMful = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	uint8_t* pSign;
	phStatus_t status = phalMful_ReadSign(palMful, 0x00, &pSign, sigLen);
	if(status){
		return status;
	}
	memcpy(sig, pSign, *sigLen);
	return status;
}

phStatus_t ultralight_write_sig(uint8_t addr, uint8_t *sign){
	void* palMful = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	return phalMful_WriteSign(palMful, addr, sign);
}

phStatus_t ultralight_lock_sig(uint8_t bLockMode){
	void* palMful = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	return phalMful_LockSign(palMful, bLockMode);
}

phStatus_t ultralight_get_version(uint8_t* ver, uint8_t *vLen){
	void* palMful = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	phStatus_t status = phalMful_GetVersion(palMful, ver);
	if(status){
		return status;
	}
	*vLen = 8;
	return status;
}

phStatus_t ultralight_check_tearing_event(uint8_t bCntNum, uint8_t *pValidFlag){
	void* palMful = phNfcLib_GetDataParams(PH_COMP_AL_MFUL);
	return phalMful_ChkTearingEvent(palMful, bCntNum, pValidFlag);
}

/*============================================================*/
/*
1.5.11.1. MifareUltralight_ReadPage
Command: [0C00][Byte: Page]
Response: [00][Bool: Result][Byte Array(16): Data]
Example
Command: 0C0004
(Page: 04)
Response: 000100010203147870672E636F6D3A636172
(Result: true, Data: 00010203147870672E636F6D3A636172)
*/
static int api_ultralight_read	(buffer_t* command, buffer_t* response){
	uint8_t page = net_buf_simple_pull_u8(command);
	uint8_t* data = net_buf_simple_tail(response);
	phStatus_t status = ultralight_read(page, data);
	API_CHECK(status);
	net_buf_simple_add(response, 16);
	return ERR_NONE;
}

/*---------------------------------------------------------------------------*/
/*
1.5.11.2. MifareUltralight_WritePage
Command: [0C01][Byte: Page][Byte Array(4): Data]
Response: [00][Bool: Result]
Example
Command: 0C010400010203
(Page: 04, Data: 00010203)
Response: 0001
(Result: true)
*/
static int api_ultralight_write	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t Page;
		uint8_t Data[4];
	}ultralight_write_param_t;
	ultralight_write_param_t* param = (ultralight_write_param_t*) command->data;
	phStatus_t status = ultralight_write(param->Page, param->Data);
	API_CHECK(status);
	return ERR_NONE;
}
/*---------------------------------------------------------------------------*/
/*
1.5.11.3. MifareUltralightC_Authenticate
Command: [0C02][Byte Array(16): Key]
Response: [00][Bool: Result]
Example
Command: 0C0249454D4B41455242214E4143554F5946
(Key: 49454D4B41455242214E4143554F5946)
Response: 0001
(Result: true)

*/
static int api_ultralight_authenticate_ulc	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t Key[16];
	}ultralight_authenticate_ulc_param_t;
	ultralight_authenticate_ulc_param_t* param = (ultralight_authenticate_ulc_param_t*) command->data;
	phStatus_t status = ultralight_authenticate_ulc(param->Key);
	API_CHECK(status);
	return ERR_NONE;
}

/*---------------------------------------------------------------------------*/
/*
1.5.11.6. MifareUltralightEV1_FastRead
Command: [0C05][Byte: StartPage][Byte: NumberOfPages]
Response: [00][Bool: Result][Byte Array(Var): Data]
Example
Command: 0C050401
(StartPage: 04, NumberOfPages: 01)
Response: 00010400000000
(Result: true, Data: 00000000)
*/
static int api_ultralight_fast_read	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t StartPage;
		uint8_t NumberOfPages;
	}ultralight_fast_read_param_t;
	ultralight_fast_read_param_t* param = (ultralight_fast_read_param_t*) command->data;
	LOGD(NULL, "StartPage=%d,NumberOfPages=%d", param->StartPage, param->NumberOfPages);
	uint8_t* data = net_buf_simple_tail(response);
	phStatus_t status = ultralight_fast_read(param->StartPage, param->NumberOfPages, data);
	API_CHECK(status);
	uint16_t dlen = param->NumberOfPages * 4;
	LOG_BUFS("data", data, dlen);
	net_buf_simple_push_u8(response, (uint8_t)dlen);
	net_buf_simple_add(response, dlen);
	return ERR_NONE;
}

/*---------------------------------------------------------------------------*/
/*
1.5.11.7. MifareUltralightEV1_IncCounter
Command: [0C06][Byte: CounterAddr][UInt32: IncrValue]
Response: [00][Bool: Result]
Example
Command: 0C060000000000
(CounterAddr: 00, IncrValue: 00000000)
Response: 0001
(Result: true)

*/
static int api_ultralight_inc_counter	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t CounterAddr;
		uint32_t IncrValue;
	}ultralight_inc_counter_param_t;
	ultralight_inc_counter_param_t* param = (ultralight_inc_counter_param_t*) command->data;
	LOGD(NULL, "CounterAddr=%d,IncrValue=%d", param->CounterAddr, param->IncrValue);
	phStatus_t status = ultralight_inc_counter(param->CounterAddr, param->IncrValue);
	API_CHECK(status);
	return ERR_NONE;
}
/*---------------------------------------------------------------------------*/
/*
1.5.11.8. MifareUltralightEV1_ReadCounter
Command: [0C07][Byte: CounterAddr]
Response: [00][Bool: Result][UInt32: CounterValue]
Example
Command: 0C0700
(CounterAddr: 00)
Response: 000102000000
(Result: true, CounterValue: 2)
*/
static int api_ultralight_read_counter	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t CounterAddr;
	}ultralight_read_counter_param_t;
	ultralight_read_counter_param_t* param = (ultralight_read_counter_param_t*) command->data;
	LOGD(NULL, "CounterAddr=%d", param->CounterAddr);
	uint8_t* data = net_buf_simple_tail(response);
	phStatus_t status = ultralight_read_counter(param->CounterAddr, data);
	API_CHECK(status);
	net_buf_simple_add(response, 4);
	return ERR_NONE;
}
/*---------------------------------------------------------------------------*/
/*
1.5.11.9. MifareUltralightEV1_ReadSig
Command: [0C08]
Response: [00][Bool: Result][Byte Array(32): ECCSig]
Example
Command: 0C08
Response: 00013A4F2622AF2039E47F8AA1BF84C52EE949860DD07125BEF75EC4-
17833B80C105
(Result: true, ECCSig:
3A4F2622AF2039E47F8AA1BF84C52EE949860DD07125BEF75EC417833B80C105)
*/
static int api_ultralight_read_sig	(buffer_t* command, buffer_t* response){
	uint8_t* data = net_buf_simple_tail(response);
	uint16_t sigLen;
	phStatus_t status = ultralight_read_sig(data, &sigLen);
	API_CHECK(status);
	LOG_BUFS("Sign", data, sigLen);
	net_buf_simple_add(response, sigLen);
	return ERR_NONE;
}
/*---------------------------------------------------------------------------*/
/*
1.5.11.10. MifareUltralightEV1_GetVersion
Command: [0C09]
Response: [00][Bool: Result][Byte Array(8): Version]
Example
Command: 0C09
Response: 00010004030101000E03
(Result: true, Version: 0004030101000E03)
*/
static int api_ultralight_get_version	(buffer_t* command, buffer_t* response){
	uint8_t* data = net_buf_simple_tail(response);
	uint8_t vLen;
	phStatus_t status = ultralight_get_version(data, &vLen);
	API_CHECK(status);
	LOG_BUFS("Version", data, vLen);
	net_buf_simple_add(response, vLen);
	return ERR_NONE;
}
/*---------------------------------------------------------------------------*/
/*
1.5.11.11. MifareUltralightEV1_PwdAuth
Command: [0C0A][Byte Array(4): Password][Byte Array(2): PwdAck]
Response: [00][Bool: Result]
Example
Command: 0C0AFFFFFFFF0000
(Password: FFFFFFFF, PwdAck: 0000)
Response: 0001
(Result: true)
*/
static int api_ultralight_authenticate_pwd(buffer_t * command, buffer_t * response)	{
	typedef struct __PACKED  {
		uint8_t Pwd[4];
		uint8_t PwdAck[2];
	}ultralight_authenticate_pwd_param_t;
	ultralight_authenticate_pwd_param_t* param = (ultralight_authenticate_pwd_param_t*) command->data;
	LOG_BUFS("Pwd", param->Pwd, sizeof(param->Pwd));
	LOG_BUFS("PwdAck", param->PwdAck, sizeof(param->PwdAck));
	uint8_t pack[4];
	phStatus_t status = ultralight_authenticate_pwd(param->PwdAck, pack);
	API_CHECK(status);
	LOG_BUFS("pack", pack, 2);
	if(memcmp(param->PwdAck, pack, sizeof(param->PwdAck))){
		LOG_E("pack error!!");
		return -2;
	}
	return ERR_NONE;
}
/*---------------------------------------------------------------------------*/
/*
1.5.11.12. MifareUltralightEV1_CheckTearingEvent
Command: [0C0B][Byte: CounterAddr]
Response: [00][Bool: Result][Byte: ValidFlag]
Example
Command: 0C0B00
(CounterAddr: 00)
Response: 0001BD
(Result: true, ValidFlag: 189)

*/
static int api_ultralight_check_tearing_event(buffer_t * command, buffer_t * response)	{
	typedef struct __PACKED  {
		uint8_t CounterAddr;
	}ultralight_check_tearing_event_param_t;
	ultralight_check_tearing_event_param_t* param = (ultralight_check_tearing_event_param_t*) command->data;
	LOG_D("CounterAddr=%d", param->CounterAddr);
	uint8_t* pValidFlag = net_buf_simple_tail(response);
	phStatus_t status = ultralight_check_tearing_event(param->CounterAddr, pValidFlag);
	API_CHECK(status);
	LOG_D("ValidFlag=%d", *pValidFlag);
	net_buf_simple_add(response, 1);
	return ERR_NONE;
}

/*---------------------------------------------------------------------------*/
/*
MifareUltralight_AuthenticateAES
Command: [0C82][Byte Array(16): Key]
Response: [00][Bool: Result]
*/
static int api_ultralight_authenticate_aes(buffer_t * command, buffer_t * response)	{
	typedef struct __PACKED  {
		uint8_t keyId;
		uint8_t Key[16];
	}ultralight_authenticate_aes_param_t;
	ultralight_authenticate_aes_param_t* param = (ultralight_authenticate_aes_param_t*) command->data;
	LOG_D("keyId=%d", param->keyId);
	LOG_BUFS("Key", param->Key, sizeof(param->Key));
	phStatus_t status = ultralight_authenticate_aes(param->keyId, param->Key);
	API_CHECK(status);
	return ERR_NONE;
}
/*---------------------------------------------------------------------------*/
/*
MifareUltralightAES_WriteSig
Command: [0C80][Byte: Addr][Byte Array(4): Sign]
Response: [00][Bool: Result]
*/
static int api_ultralight_write_sig	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t Addr;
		uint8_t Sign[4];
	}ultralight_write_sig_param_t;
	ultralight_write_sig_param_t* param = (ultralight_write_sig_param_t*)command->data;
	LOGD("Addr", "%d", param->Addr);
	LOG_BUFS("Sign", param->Sign, sizeof(param->Sign));
	phStatus_t status = ultralight_write_sig(param->Addr, param->Sign);
	API_CHECK(status);
	return ERR_NONE;
}

/*---------------------------------------------------------------------------*/
/*
MifareUltralightAES_LockSig
Command: [0C81][Byte: Mode]
Response: [00][Bool: Result]
*/
static int api_ultralight_lock_sig	(buffer_t* command, buffer_t* response){
	typedef struct __PACKED  {
		uint8_t Mode;
	}ultralight_lock_sig_param_t;
	ultralight_lock_sig_param_t* param = (ultralight_lock_sig_param_t*)command->data;
	phStatus_t status = ultralight_lock_sig(param->Mode);
	API_CHECK(status);
	return ERR_NONE;
}
/*---------------------------------------------------------------------------*/
enum {
	API_ULTRALIGHT_READ = 0,
	API_ULTRALIGHT_WRITE = 1,
	API_ULTRALIGHT_AUTH_ULC = 2,
	API_ULTRALIGHT_FAST_READ = 5,
	API_ULTRALIGHT_INC_COUNTER = 6,
	API_ULTRALIGHT_READ_COUNTER = 7,
	API_ULTRALIGHT_READ_SIG = 8,
	API_ULTRALIGHT_GET_VERSION = 9,
	API_ULTRALIGHT_AUTH_PWD = 0x0A,
	API_ULTRALIGHT_CHK_TEARING_EVENT = 0x0B,
	
	API_ULTRALIGHT_WRITE_SIG = 0x80,
	API_ULTRALIGHT_LOCK_SIG = 0x81,
	API_ULTRALIGHT_AUTH_AES = 0x82,
};

static const api_func_t api_ultralight_list[] = {
	{API_ULTRALIGHT_READ, api_ultralight_read},
	{API_ULTRALIGHT_WRITE, api_ultralight_write},
	{API_ULTRALIGHT_AUTH_ULC, api_ultralight_authenticate_ulc},
	{API_ULTRALIGHT_FAST_READ, api_ultralight_fast_read},
	{API_ULTRALIGHT_INC_COUNTER, api_ultralight_inc_counter},
	{API_ULTRALIGHT_READ_COUNTER, api_ultralight_read_counter},
	{API_ULTRALIGHT_READ_SIG, api_ultralight_read_sig},
	{API_ULTRALIGHT_GET_VERSION, api_ultralight_get_version},
	{API_ULTRALIGHT_AUTH_PWD, api_ultralight_authenticate_pwd},
	{API_ULTRALIGHT_CHK_TEARING_EVENT, api_ultralight_check_tearing_event},
	
	{API_ULTRALIGHT_WRITE_SIG, api_ultralight_write_sig},
	{API_ULTRALIGHT_LOCK_SIG, api_ultralight_lock_sig},
	{API_ULTRALIGHT_AUTH_AES, api_ultralight_authenticate_aes},
};

static int ultralight_call_api(buffer_t* command, buffer_t* response){
	const uint8_t fun = net_buf_simple_pull_u8(command);
	const uint8_t func_num = sizeof(api_ultralight_list)/sizeof(api_ultralight_list[0]);
	
	for(int i = 0; i < func_num; i++){
		if(api_ultralight_list[i].func == fun){
			return api_ultralight_list[i].entry(command, response);
		}
	}
	
	return ERR_INVALID_FUNCTION;
}

static int ultralight_api(buffer_t* command, buffer_t* response){
	int ret = ultralight_call_api(command, response);
	if(ret > 0){
		return ret;
	}
	protocol_response_result(response, ret);
	return ERR_NONE;
}

SIMPLE_API_DEFINE(API_CLASS_MIFARE_ULTRALIGHT, ultralight_api);


